package com.clei.netty.util;

import com.clei.consts.NettyConstants;
import com.clei.utils.PrintUtil;
import com.clei.utils.ThreadUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * 文件数据管理器
 *
 * @author Y
 * @date 2022-04-22
 */
public class FileDataManager {

    /**
     * fileId -> FileWriteRecord map
     */
    private static final Map<Integer, FileWriteRecord> RECORDER = new ConcurrentHashMap<>();

    /**
     * 线程池
     */
    private static final ThreadPoolExecutor EXECUTOR = ThreadUtil.pool(Integer.MAX_VALUE);

    /**
     * 存入文件数据容器
     *
     * @param fileId          文件名
     * @param capacity        文件数据list容量
     * @param filePath        文件路径
     * @param override        是否覆盖
     * @param callbackHandler 上传文件完成回调处理器
     * @re
     */
    public static String put(Integer fileId, Integer capacity, String filePath, boolean override, Consumer<Integer> callbackHandler) {
        // fileName
        String newFileName = null;
        if (!override) {
            File file = new File(filePath);
            if (file.exists()) {
                String fileName = file.getName();
                int dotIndex = fileName.lastIndexOf('.');
                String suffix;
                if (-1 == dotIndex) {
                    dotIndex = fileName.length();
                    suffix = "";
                } else {
                    suffix = fileName.substring(dotIndex);
                }
                String prefix = fileName.substring(0, dotIndex);
                File parentFile = file.getParentFile();
                long count = Arrays.stream(Objects.requireNonNull(parentFile.list()))
                        .filter(n -> n.startsWith(prefix)).count();
                newFileName = prefix + "(" + count + ")" + suffix;
                filePath = filePath.replace(fileName, newFileName);
            }
        }

        RandomAccessFile randomAccessFile = null;
        try {
            randomAccessFile = new RandomAccessFile(filePath, "rws");
        } catch (FileNotFoundException e) {
            PrintUtil.log("new RandomAccessFile error filePath : {}", filePath, e);
        }

        RECORDER.put(fileId, new FileWriteRecord(randomAccessFile, new AtomicInteger(), capacity, callbackHandler));
        return newFileName;
    }

    /**
     * 存入文件数据
     *
     * @param fileId 文件名
     * @param index  数据位置
     * @param data   文件数据
     */
    public static void add(Integer fileId, int index, byte[] data) {
        EXECUTOR.execute(() -> {
            // file
            FileWriteRecord record = RECORDER.get(fileId);
            RandomAccessFile randomAccessFile = record.getFile();
            try {
                randomAccessFile.seek((long) index * NettyConstants.FILE_BUFFER_SIZE);
                randomAccessFile.write(data);
            } catch (Exception e) {
                PrintUtil.log("RandomAccessFile write error fileId : {}, index : {}", fileId, index, e);
            }
            // counter
            int writeCount = record.getCounter().incrementAndGet();
            // 大小等于容量的时候 说明上传完毕
            if (writeCount == record.getCapacity()) {
                // 清理
                RECORDER.remove(fileId);
                Consumer<Integer> handler = record.getCallbackHandler();
                handler.accept(fileId);
                try {
                    randomAccessFile.close();
                } catch (Exception e) {
                    PrintUtil.log("RandomAccessFile close error fileId : {}", fileId, e);
                }
            }
        });
    }
}
